package code.lucamarrocco.rest;

import static java.util.Arrays.asList;

import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Matchers {
	public static RestfulMethod apply(String uri, RestfulMethod restfulMethod) {
		RestfulMethod newRestfulMethod = restfulMethod.newRestfulMethod();

		String pattern = newRestfulMethod.getPattern();
		Collection<String> parameterNames = newRestfulMethod.getNames();

		pattern = pattern.replaceAll("\\{[^\\{\\}/]*\\}", "([^/]*)");

		uri = uri.replaceAll("^POST ", "");
		uri = uri.replaceAll("^GET ", "");
		uri = uri.replaceAll("^PUT ", "");
		uri = uri.replaceAll("^DELETE ", "");

		String regex = "^" + pattern + ".*$";

		Matcher matcher = Pattern.compile(regex).matcher(uri);

		if (!matcher.matches()) throw new RuntimeException(restfulMethod + " does not matches " + uri);

		int i = 1;

		Object value;
		for (String parameterName : parameterNames) {
			value = matcher.group(i++);
			newRestfulMethod.setParameter(parameterName, value);
		}
		
		newRestfulMethod.setUri(uri);

		return newRestfulMethod;
	}

	private static int brakets(String pattern) {
		int brackets = 0, close = 0;

		for (int i = 0; i < pattern.length(); i++) {
			if (pattern.charAt(i) == '{') brackets++;
		}

		for (int i = 0; i < pattern.length(); i++) {
			if (pattern.charAt(i) == '}') close++;
		}

		if (brackets != close) throw new RuntimeException("open { must match with close }");

		return brackets;
	}

	public static final List<String> matchersOf(RestfulMethod method) {
		List<String> matchers = new LinkedList<String>();

		String pattern = method.getPattern();

		String[] paramterNames = parameterNames(pattern);

		String matcher = method.toString();

		matcher = matcher.replaceAll("/\\*", "/(.*)");

		for (int i = 0; i < paramterNames.length; i++) {
			matcher = matcher.replaceAll("/\\{" + paramterNames[i] + "\\}", "/([^/]*)");
			matcher = matcher.replaceAll("\\{" + paramterNames[i] + "\\}", "([^/]*)");
			matcher = matcher.replaceAll("\\{" + paramterNames[i] + "\\}", "([^/]*)");
		}

		if(matcher.endsWith("/(.*)")) matchers.add(matcher.replaceAll("/\\(\\.\\*\\)", ""));
		
		matchers.add(matcher);

		return matchers;
	}

	private static String[] parameterNames(String pattern) {
		int brackets = brakets(pattern);

		String[] parameterNames = new String[brackets];
		for (int i = 0; i < brackets; i++) {
			String parameterName = pattern;
			for (int j = 0; j < i + 1; j++)
				parameterName = parameterName.substring(parameterName.indexOf('{') + 1);
			if (parameterName.indexOf("}") > 0) parameterName = parameterName.substring(0, parameterName.indexOf("}"));
			parameterNames[i] = parameterName;
		}

		return parameterNames;
	}

	public static final Map<String, Object> parameters(String pattern) {
		Map<String, Object> parameters = new LinkedHashMap<String, Object>();

		for (String parameterName : asList(parameterNames(pattern))) {
			if (parameterName.endsWith("Id")) parameters.put(parameterName, 0l);
			if (!parameterName.endsWith("Id")) parameters.put(parameterName, "");
		}

		return parameters;
	}
}
